package com.fast.fast.upms.biz.base.util;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.tika.Tika;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.sax.BodyContentHandler;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Optional;

/**
 * tika工具类
 *
 * @author lyf
 * @date 2021/12/26 00:00
 * @date 2024/10/14 16点51分
 **/
@Slf4j
@UtilityClass
public class TikaUtils {

    /**
     * 快速解析
     *
     * @param inputStream 输入流
     * @return 文档正文
     */
    @SneakyThrows
    public static String fastParse(InputStream inputStream) {
        return new Tika().parseToString(inputStream);
    }

    /**
     * 快速解析
     *
     * @param file 文件对象
     * @return 文档正文
     */
    @SneakyThrows
    public static String fastParse(File file) {
        return new Tika().parseToString(file);
    }

    /**
     * 快速解析
     *
     * @param path 文件路径
     * @return 文档正文
     */
    public static String fastParse(String path) {
        return fastParse(new File(path));
    }

    /**
     * 自定义解析
     *
     * @param inputStream 输入流
     * @return 文档正文
     */
    public static String parse(InputStream inputStream) {
        BodyContentHandler handler = (BodyContentHandler) startParse(inputStream).get("handler");
        return handler.toString();
    }

    /**
     * 自定义解析
     *
     * @param file 文件对象
     * @return 文档正文
     */
    @SneakyThrows
    public static String parse(File file) {
        try (InputStream inputStream = new FileInputStream(file)) {
            return parse(inputStream);
        }
    }

    /**
     * 自定义解析
     *
     * @param path 文件路径
     * @return 文档正文
     */
    public static String parse(String path) {
        return parse(new File(path));
    }

    /**
     * 开始解析
     *
     * @param inputStream 输入流
     * @return
     */
    @SneakyThrows
    private static JSONObject startParse(InputStream inputStream) {
        //  正文处理器
        BodyContentHandler handler = new BodyContentHandler();
        //  元数据
        Metadata metadata = new Metadata();
        //  解析器
        AutoDetectParser parser = new AutoDetectParser();
        //  开始解析
        parser.parse(inputStream, handler, metadata);
        JSONObject rs = new JSONObject(true);
        rs.put("handler", handler);
        rs.put("metadata", metadata);
        return rs;
    }

    /**
     * 开始解析
     *
     * @param file 文件对象
     * @return
     */
    @SneakyThrows
    private static JSONObject startParse(File file) {
        try (InputStream inputStream = new FileInputStream(file)) {
            return startParse(inputStream);
        }
    }

    /**
     * 开始解析
     *
     * @param path 文件路径
     * @return
     */
    private static JSONObject startParse(String path) {
        return startParse(new File(path));
    }

    /**
     * 获取文件内容类型
     * doc、docx：application/vnd.openxmlformats-officedocument.wordprocessingml.document
     * xls xlsx：application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
     * ppt pptx：application/vnd.openxmlformats-officedocument.presentationml.presentation
     * pdf：application/pdf
     * txt：text/plain
     * audio: audio/xxx
     * <p>
     * video:
     * 3gp：video/3gpp
     * flv：video/x-flv
     * mpg：video/mpeg
     * vob：video/mpeg
     * mp4：video/mp4
     * mkv：video/x-matroska
     * mov：video/quicktime
     * avi：video/x-msvideo
     * wmv: video/x-ms-wmv
     * <p>
     * image: image/xxx
     *
     * @param inputStream 输入流
     * @return 文件类型
     */
    public static String getContentType(InputStream inputStream) {
        Metadata metadata = (Metadata) startParse(inputStream).get("metadata");
        return metadata.get("Content-Type");
    }

    /**
     * 获取文件内容类型
     *
     * @param file 文件对象
     * @return 文件类型
     */
    @SneakyThrows
    public static String getContentType(File file) {
        try (InputStream inputStream = new FileInputStream(file)) {
            return getContentType(inputStream);
        }
    }

    /**
     * 获取文件内容类型
     *
     * @param path 文件路径
     * @return 文件类型
     */
    public static String getContentType(String path) {
        return getContentType(new File(path));
    }

    /**
     * 获取文件内容类型
     *
     * @param metadata 元数据
     * @return 文件类型
     */
    public static String getContentType(Metadata metadata) {
        return metadata.get("Content-Type");
    }

    @NotNull
    private static String getAuthorExtract(Metadata metadata) {
        String author = metadata.get("Author");
        if (ObjUtil.isEmpty(author)) {
            author = metadata.get("creator");
            if (ObjUtil.isEmpty(author)) {
                author = metadata.get("Last-Author");
            }
        }
        return author == null ? "" : author;
    }

    /**
     * 获取作者
     *
     * @param inputStream 输入流
     * @return 作者名
     */
    public static String getAuthor(InputStream inputStream) {
        Metadata metadata = (Metadata) startParse(inputStream).get("metadata");
        return getAuthorExtract(metadata);
    }

    /**
     * 获取作者
     *
     * @param file 文件对象
     * @return 作者名
     */
    @SneakyThrows
    public static String getAuthor(File file) {
        try (InputStream inputStream = new FileInputStream(file)) {
            return getAuthor(inputStream);
        }
    }

    /**
     * 获取作者
     *
     * @param path 文件路径
     * @return 作者名
     */
    public static String getAuthor(String path) {
        return getAuthor(new File(path));
    }

    /**
     * 获取作者
     *
     * @param metadata 元数据
     * @return 作者名
     */
    public static String getAuthor(Metadata metadata) {
        return getAuthorExtract(metadata);
    }

    /**
     * 获取文本字数
     *
     * @param text 文本
     * @return 文本字数
     */
    public static int wordsCount(String text) {
        // 匹配汉字、字母或数字或下划线
        String reg = "[\\u4e00-\\u9fa5\\w]";
        int result = 0;
        for (int i = 0; i < text.length(); i++) {
            if (String.valueOf(text.charAt(i)).matches(reg)) {
                result++;
            }
        }
        return result;
    }

    /**
     * 获取多媒体文件的播放时长
     *
     * @param inputStream 输入流
     * @return 多媒体文件的播放时长
     */
    public static String getMediaDuration(InputStream inputStream) {
        Metadata metadata = (Metadata) startParse(inputStream).get("metadata");
        return String.valueOf(NumberUtil.parseInt(metadata.get("xmpDM:duration")));
    }

    /**
     * 获取多媒体文件的播放时长
     *
     * @param file 文件对象
     * @return 多媒体文件的播放时长
     */
    @SneakyThrows
    public static String getMediaDuration(File file) {
        try (InputStream inputStream = new FileInputStream(file)) {
            return getMediaDuration(inputStream);
        }
    }

    /**
     * 获取多媒体文件的播放时长
     *
     * @param path 文件路径
     * @return 多媒体文件的播放时长
     */
    public static String getMediaDuration(String path) {
        return getMediaDuration(new File(path));
    }

    /**
     * 获取多媒体文件的播放时长
     *
     * @param metadata 元数据
     * @return 多媒体文件的播放时长
     */
    public static String getMediaDuration(Metadata metadata) {
        return String.valueOf(NumberUtil.parseInt(metadata.get("xmpDM:duration")));
    }

    /**
     * 获取文件信息
     *
     * @param file 文件对象
     * @return 文件信息
     */
    @SneakyThrows
    public static JSONObject getFileInfo(File file) {
        JSONObject rs = new JSONObject(true);

        // 原始文件名
        String title = file.getName();
        // 文件格式
        String format = title.substring(title.lastIndexOf(".") + 1);
        // 文件名
        String name = SecureUtil.md5(file) + "." + format;
        // 文件大小,单位:KB
        String size = String.valueOf(file.length() / 1024);

        JSONObject jo = startParse(file);
        BodyContentHandler handler = (BodyContentHandler) jo.get("handler");
        Metadata metadata = (Metadata) jo.get("metadata");

        rs.put("contentType", getContentType(metadata));
        rs.put("title", title);
        rs.put("name", name);
        rs.put("format", format);
        rs.put("author", getAuthor(metadata));
        rs.put("wordsCount", Optional.ofNullable(metadata.get("Character Count"))
                .orElse(String.valueOf(wordsCount(handler.toString())))
        );
        rs.put("mediaDuration", getMediaDuration(metadata));
        rs.put("size", size);
        rs.put("path", file.getCanonicalPath());
        rs.put("content", handler.toString());
        return rs;
    }

    /**
     * 获取文件信息
     *
     * @param path 文件路径
     * @return 文件信息
     */
    public static JSONObject getFileInfo(String path) {
        return getFileInfo(new File(path));
    }

}
